#include <stdlib.h>
#include <cstring>
#include <cstdarg>
#include "buffer.h"

using namespace VLRTSP;

/**
 * @Author: CimZzz
 * @Date: 2022-01-07 14:14:06
 * 
 * 构造函数，初始化缓冲长度
 * @param initSize 初始化缓冲长度
 */
Buffer::Buffer(uint32_t initSize) {
	this->buffer = new uint8_t[initSize];
	this->bufferLength = 0;
	this->totalLength = initSize;
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-07 14:21:04
 * 
 * 析构函数
 * 回收缓冲资源
 */
Buffer::~Buffer() {
	delete buffer;
}


/**
 * @Author: CimZzz
 * @Date: 2022-01-07 17:02:46
 * 
 * 获取当前缓冲长度
 * @return 缓冲长度
 */
uint32_t Buffer::getBufferLength() {
	return this->bufferLength;
}


/**
 * @Author: CimZzz
 * @Date: 2022-01-10 16:57:05
 * 
 * 获取当前缓冲区已申请的内存长度
 * @return 已申请的内存长度
 */
uint32_t Buffer::getTotalLength() {
	return this->totalLength;
}


/**
 * @Author: CimZzz
 * @Date: 2022-01-10 17:06:07
 * 
 * 重置当前内存缓冲区
 */
void Buffer::reset() {
	this->bufferLength = 0;
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-07 14:29:07
 * 
 * 复制字节到当前缓冲区中
 * @param buffer 字节数组指针
 * @param offset 偏移位置
 * @param length 复制长度
 */
void Buffer::appendBuffer(const uint8_t* buffer, uint32_t offset, uint32_t length) {
	this->_appendBuffer(this->bufferLength, buffer, offset, length);
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-07 14:29:07
 * 
 * 复制字节到当前缓冲区中
 * @param buffer 字节缓冲区
 * @param offset 偏移位置
 * @param length 复制长度，0 表示复制到末尾
 */
void Buffer::appendBuffer(const Buffer* buffer, uint32_t offset, uint32_t length) {
	if(offset >= buffer->bufferLength) {
		throw "Not enough bytes can be copied!";
	}


	uint32_t realLength = 0;
	if(length != 0) {
		if(offset + length > buffer->bufferLength) {
			throw "Not enough bytes can be copied!";
		}
		realLength = length;
	} else {
		realLength = buffer->bufferLength - offset;
	}

	this->appendBuffer(buffer->buffer, offset, realLength);
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-07 15:58:10
 * 
 * 复制单字节到当前缓冲区中
 * @param byte 单字节
 */
void Buffer::appendByte(uint8_t byte) {
	this->_appendBuffer(this->bufferLength, &byte, 0, 1);
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-14 15:24:27
 * 
 * 在当前缓冲区中插入字节
 * @param insertIndex 插入位置
 * @param buffer 字节数组指针
 * @param offset 偏移位置
 * @param length 复制长度
 * 
 * @note 如果插入位置超过当前字节长度，那么缓存字节长度会变更到插入之后的字节尾部，中间间隔部分会填充 0
 */
void Buffer::insertBuffer(uint32_t insertIndex, const uint8_t* buffer, uint32_t offset, uint32_t length) {
	this->_appendBuffer(insertIndex, buffer, offset, length);
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-14 15:25:13
 * 
 * 在当前缓冲区中插入字节
 * @param insertIndex 插入位置
 * @param buffer 字节缓冲区
 * @param offset 偏移位置
 * @param length 复制长度，0 表示复制到末尾
 * 
 * @note 如果插入位置超过当前字节长度，那么缓存字节长度会变更到插入之后的字节尾部，中间间隔部分会填充 0
 */
void Buffer::insertBuffer(uint32_t insertIndex, const Buffer* buffer, uint32_t offset, uint32_t length) {
	if(offset >= buffer->bufferLength) {
		throw "Not enough bytes can be copied!";
	}
	uint32_t realLength = 0;
	if(length != 0) {
		if(offset + length > buffer->bufferLength) {
			throw "Not enough bytes can be copied!";
		}
		realLength = length;
	} else {
		realLength = buffer->bufferLength - offset;
	}

	this->insertBuffer(insertIndex, buffer->buffer, offset, realLength);
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-07 15:58:10
 * 
 * 在当前缓冲区中插入单字节
 * @param insertIndex 插入位置
 * @param byte 单字节
 * 
 * @note 如果插入位置超过当前字节长度，那么缓存字节长度会变更到插入之后的字节尾部，中间间隔部分会填充 0
 */
void Buffer::appendByte(uint32_t insertIndex, uint8_t byte) {
	_appendBuffer(insertIndex, &byte, 0, 1);
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-12 17:05:13
 * 
 * 将打印的字符串添加到当前缓冲区中
 * @param fmt 格式化字符串
 * @param ... 变长参数，用于填充格式化字符串参数
 */
void Buffer::appendPrint(const char * fmt, ...) {
	va_list va;
	va_start(va, fmt);
	uint32_t size = vsnprintf(nullptr, 0, fmt, va);
	va_end(va);
	uint8_t buffer[size + 1];
	va_start(va, fmt);
	vsnprintf((char*)buffer, size + 1, fmt, va);
	va_end(va);
	this->appendBuffer(buffer, 0, size);
}


/**
 * @Author: CimZzz
 * @Date: 2022-01-11 18:54:06
 * 
 * 从字节缓冲区中移除字节
 * @param offset 偏移位置
 * @param length 移除长度
 */
void Buffer::removeRange(uint32_t offset, uint32_t length) {
	if((offset == 0 && length == 0) || (offset == 0 && length >= this->bufferLength)) {
		this->reset();
		return;
	}

	if(offset >= this->bufferLength || offset < 0) {
		return;
	}

	uint32_t end = offset + length;
	if(end >= this->bufferLength) {
		end = this->bufferLength;
	}

	if(end == this->bufferLength || length == 0) {
		// 后面全部移除
		this->bufferLength = offset;
	} else {
		// 移除开头及中间部分
		memmove(this->buffer + offset, this->buffer + end, this->bufferLength - end);
		this->bufferLength -= length;
	}
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-07 14:22:31
 * 
 * 克隆当前缓冲资源
 * @param offset 偏移位置
 * @param length 克隆长度，0 表示克隆到末尾
 */
uint8_t* Buffer::getBufferClone(uint32_t offset, uint32_t length) {
	if(offset >= this->bufferLength) {
		return nullptr;
	}

	uint32_t realLength = 0;
	if(length != 0) {
		if(offset + length > this->totalLength) {
			return nullptr;
		}
		realLength = length;
	} else {
		realLength = this->bufferLength - offset;
	}

	uint8_t* newBuffer = new uint8_t[realLength];
	memcpy(newBuffer, this->buffer + offset, realLength);
	return newBuffer;
}


/**
 * @Author: CimZzz
 * @Date: 2022-01-07 17:04:45
 * 
 * 直接获取当前缓存区指针
 * @return 缓冲区指针
 */
uint8_t* Buffer::getBuffer() const {
	return this->buffer;
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-10 16:56:37
 * 
 * 确保当前缓冲区已申请内存长度
 * @param size 已申请内存长度
 */
bool Buffer::makeSureTotalLength(uint32_t size) {
	if(this->totalLength >= size) {
		return true;
	}
	uint32_t incLength = size - this->totalLength;
	incLength = incLength < BUFFER_MIN_INC_SIZE ? BUFFER_MIN_INC_SIZE : incLength;
	this->buffer = (uint8_t *)realloc(this->buffer, incLength + this->totalLength);
	this->totalLength += incLength;
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-07 14:33:06
 * 
 * 添加指定字节到当前缓冲区指定位置中
 * @param currentOffset 当前字节缓冲区指定位置
 * @param buffer 字节数组指针
 * @param offset 偏移位置
 * @param length 转移长度
 */
void Buffer::_appendBuffer(uint32_t currentOffset, const uint8_t* buffer, uint32_t offset, uint32_t length) {
	if(buffer == nullptr) {
		return;
	}

	uint32_t incLength = 0;
	if(currentOffset >= this->totalLength) {
		incLength = length;
	}
	else if(currentOffset + length > this->totalLength) {
		incLength = currentOffset + length - this->totalLength;
	}

	if(incLength != 0) {
		incLength = incLength < BUFFER_MIN_INC_SIZE ? BUFFER_MIN_INC_SIZE : incLength;
		this->buffer = (uint8_t *)realloc(this->buffer, incLength + this->totalLength);
		this->totalLength += incLength;
	}

	memcpy(this->buffer + currentOffset, buffer + offset, length);
	if(currentOffset > this->bufferLength) {
		// 中间留白
		memset(this->buffer + this->bufferLength, 0, currentOffset - this->bufferLength);
	}
	this->bufferLength = currentOffset + length;
}